// Repeatr.cpp : Defines the entry point for the application.
//

#include "Repeatr.h"
#include <windows.h>
#include <aygshell.h>
#include <regext.h>
#include <snapi.h>

// The window messages we'll request the operating system
// to send our main window whenever a new unread message
// or missed phone call occurs.
#define WM_MISSED_CALL      (WM_USER + 1)
#define WM_UNREAD_SMS       (WM_USER + 2)
#define WM_UNREAD_EMAIL     (WM_USER + 3)
#define WM_UNREAD_VOICEMAIL (WM_USER + 4)

// A set of bitflags indicating which alerts
// are currently active.
static DWORD gbl_dwAlertStates = 0;

// Set the bitflag indicating the particular alert
// type is currently active, and update the UI
// if it is the very first alert to become active.
static void SetAlert(HWND hDlg, int alertId)
{
	// Set the bit in the alert states variable
	// to indicate this alert type is active
	gbl_dwAlertStates |= (1 << alertId);

	if (gbl_dwAlertStates == (1 << alertId))
	{
		// This was the first alert to be raised
		// so start the timer and enable the
		// clear alerts soft key.
		int interval = SendDlgItemMessage(hDlg, IDC_SPIN_INTERVAL, UDM_GETPOS, 0, 0);
	
		SetTimer(hDlg, 1, 60 * 1000 * interval, NULL);
		SHEnableSoftkey(SHFindMenuBar(hDlg), IDM_CLEARALERTS, FALSE, TRUE);
	}
}

// clear the bitflag indicating the particular alert
// type is not currently active, and update the UI
// if it is the very last alert to become inactive.
static void ClearAlert(HWND hDlg, int alertId)
{
	// Clear the bit in the alert states variable
	// to indicate this alert type is now inactive.
	// The alertId MAXLONG indicates a special
	// request to clear all active alerts.
	if (alertId == MAXLONG)
		gbl_dwAlertStates = 0;
	else
		gbl_dwAlertStates &= ~(1 << alertId);

	if (gbl_dwAlertStates == 0)
	{
		// This was the last alert to be cleared
		// so stop the timer and disable the clear
		// alerts soft key.
		KillTimer(hDlg, 1);
		SHEnableSoftkey(SHFindMenuBar(hDlg), IDM_CLEARALERTS, FALSE, FALSE);
	}
}

// Handle an alert changing states. dwNewValue is the number of
// unread messages or missed phone calls etc.
static void HandleAlert(HWND hDlg, UINT nCheckboxId, DWORD dwNewValue)
{
	int alertId = nCheckboxId - IDC_UNREAD_SMS;

	BOOL bNewState = (dwNewValue > 0); // 1 or more unread messages
	BOOL bOldState = (gbl_dwAlertStates & (1 << alertId));

	// If the state of this alert has changed
	if (bNewState != bOldState)
	{
		if (bNewState)
		{
			// Set the alert flag (but only if the user is interested)
			if (SendDlgItemMessage(hDlg, nCheckboxId, BM_GETCHECK, 0, 0) == BST_CHECKED)
				SetAlert(hDlg, alertId);
		}
		else
		{
			// Clear the alert flag
			ClearAlert(hDlg, alertId);
		}
	}
}

// Message handler for Repeatr dialog.
INT_PTR CALLBACK RepeatrDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	static HREGNOTIFY hNotifyMissedCall = NULL;
	static HREGNOTIFY hNotifyUnreadSMS = NULL;
	static HREGNOTIFY hNotifyUnreadEmail = NULL;
	static HREGNOTIFY hNotifyUnreadVoiceMail = NULL;

    switch (message)
    {
        case WM_INITDIALOG:
            {
                SHINITDLGINFO shidi;
				SHMENUBARINFO mbi;

                // Create a Done button and size it.  
                shidi.dwMask = SHIDIM_FLAGS;
                shidi.dwFlags = SHIDIF_CANCELBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN;
                shidi.hDlg = hDlg;
                SHInitDialog(&shidi);

				// Create a menu bar
                memset(&mbi, 0, sizeof(SHMENUBARINFO));
				mbi.cbSize     = sizeof(SHMENUBARINFO);
				mbi.hwndParent = hDlg;
				mbi.nToolBarId = IDR_MENU;
				mbi.hInstRes   = GetModuleHandle(NULL);
				mbi.dwFlags = SHCMBF_HMENU;
	            SHCreateMenuBar(&mbi);

				// Set min/max value of repeat interval
				// spinbox and it's current value
				SendDlgItemMessage(hDlg, IDC_SPIN_INTERVAL, UDM_SETRANGE32, 1, 60);
				SendDlgItemMessage(hDlg, IDC_SPIN_INTERVAL, UDM_SETPOS, 1, MAKEWORD(1, 0));

				// Ask the operating system to inform us whenever
				// we miss a phone call, or receive an unread sms,
				// email or voice mail message.
				RegistryNotifyWindow(SN_PHONEMISSEDCALLS_ROOT,
					SN_PHONEMISSEDCALLS_PATH,
					SN_PHONEMISSEDCALLS_VALUE,
					hDlg, WM_MISSED_CALL, 0, NULL, &hNotifyMissedCall);
				RegistryNotifyWindow(SN_MESSAGINGSMSUNREAD_ROOT,
					SN_MESSAGINGSMSUNREAD_PATH,
					SN_MESSAGINGSMSUNREAD_VALUE,
					hDlg, WM_UNREAD_SMS, 0, NULL, &hNotifyUnreadSMS);
				RegistryNotifyWindow(SN_MESSAGINGTOTALEMAILUNREAD_ROOT,
					SN_MESSAGINGTOTALEMAILUNREAD_PATH,
					SN_MESSAGINGTOTALEMAILUNREAD_VALUE,
					hDlg, WM_UNREAD_EMAIL, 0, NULL, &hNotifyUnreadEmail);
				RegistryNotifyWindow(SN_MESSAGINGVOICEMAILTOTALUNREAD_ROOT,
					SN_MESSAGINGVOICEMAILTOTALUNREAD_PATH,
					SN_MESSAGINGVOICEMAILTOTALUNREAD_VALUE,
					hDlg, WM_UNREAD_VOICEMAIL, 0, NULL, &hNotifyUnreadVoiceMail);
	           }
            return (INT_PTR)TRUE;

        case WM_COMMAND:
			switch (LOWORD(wParam))
			{
			case IDOK:
                EndDialog(hDlg, LOWORD(wParam));
                return (INT_PTR)TRUE;

			case IDCANCEL:
				// Minimise the dialog
				ShowWindow(hDlg, SW_MINIMIZE);
				return (INT_PTR)TRUE;

			case IDM_CLEARALERTS:
				// Clear all active alerts
				ClearAlert(hDlg, MAXLONG);
				return (INT_PTR)TRUE;

			case IDC_MISSED_CALL:
			case IDC_UNREAD_SMS:
			case IDC_UNREAD_EMAIL:
			case IDC_UNREAD_VOICEMAIL:
				if (HIWORD(wParam) == BN_CLICKED)
				{
					// If the user unchecks one of the checkboxes we'll
					// clear the alert. This will stop the timer playing
					// sound effects if the alert type was currently active
					// and is harmless if the alert wasn't currently set.
					int alertId = (LOWORD(wParam) - IDC_UNREAD_SMS);
					if (SendDlgItemMessage(hDlg, LOWORD(wParam), BM_GETCHECK, 0, 0) == BST_UNCHECKED)
						ClearAlert(hDlg, alertId);
				}
				break;
            }
            break;

		case WM_TIMER:
			{
			// Play the reminder sound effect
			TCHAR szFullPath[MAX_PATH];
			GetModuleFileName(GetModuleHandle(NULL), szFullPath, MAX_PATH);
			wcscpy(wcsrchr(szFullPath, '\\') + 1, _T("alert.wav"));
			PlaySound(szFullPath, NULL, SND_FILENAME | SND_ASYNC);
			}
			break;

		case WM_MISSED_CALL:
			HandleAlert(hDlg, IDC_MISSED_CALL, wParam);
			break;

		case WM_UNREAD_SMS:
			HandleAlert(hDlg, IDC_UNREAD_SMS, wParam);
			break;

		case WM_UNREAD_EMAIL:
			HandleAlert(hDlg, IDC_UNREAD_EMAIL, wParam);
			break;

		case WM_UNREAD_VOICEMAIL:
			HandleAlert(hDlg, IDC_UNREAD_VOICEMAIL, wParam);
			break;

        case WM_CLOSE:
			RegistryCloseNotification(hNotifyMissedCall);
			RegistryCloseNotification(hNotifyUnreadSMS);
			RegistryCloseNotification(hNotifyUnreadEmail);
			RegistryCloseNotification(hNotifyUnreadVoiceMail);

			hNotifyMissedCall = NULL;
			hNotifyUnreadSMS = NULL;
			hNotifyUnreadEmail = NULL;
			hNotifyUnreadVoiceMail = NULL;

            EndDialog(hDlg, message);
            return (INT_PTR)TRUE;

    }
    return (INT_PTR)FALSE;
}

int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   int       nCmdShow)
{
	return DialogBox(hInstance, (LPCTSTR)IDD_REPEATR, NULL, RepeatrDialog);
}